package creational.pattern.factory.factories;




import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import creational.pattern.factory.help.BeanDefinition;

import org.apache.commons.collections4.CollectionUtils;
import static com.google.common.base.Preconditions.*;

/**
 * @Author yoyuan
 * @Description: Spring中BeanFactory的方法
 * @DateTime: 2023/1/8 15:58
 */
public class BeanFactory {
    // spring框架中的额bean对象是通过beanDefinition构造的
    // final修饰的对象，内容可以变，引用地址不变
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    private final Map<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>();


    // 通过开放add接口替代static的方法
    public void addBeanDefinitions(List<BeanDefinition> beanDefinitionList){
        for (BeanDefinition beanDefinition : beanDefinitionList){
            this.beanDefinitions.putIfAbsent(beanDefinition.getClassName(), beanDefinition);
        }
        // 如果是单例，应该直接创建
        for (BeanDefinition beanDefinition : beanDefinitionList){
            if (!beanDefinition.isLazyInit() && beanDefinition.isSingleton()){
                createBean(beanDefinition);
            }
        }
    }
    public Object getBean(String beanId){
        BeanDefinition beanDefinition = beanDefinitions.get(beanId);
        if (beanDefinition == null){
            throw new NoSuchElementException("bean is not defined");
        }
        return createBean(beanDefinition);
    }

    // 因为不知道要创建的对象是谁，所以使用反射进行对象的创建
    private Object createBean(BeanDefinition beanDefinition) {
        if (beanDefinition.isSingleton() && singletonObjects.containsKey(beanDefinition.getId())){
            return singletonObjects.get(beanDefinition.getClassName());
        }
        Object result = null;
        try {
            // 1、获取对象的类名
            Class<?> beanClass = Class.forName(beanDefinition.getClassName());

            // 2、得到所有构造函数的相应参数
            List<BeanDefinition.ConstructorArg> constructorArgs = beanDefinition.getConstructors();
            if (CollectionUtils.isEmpty(constructorArgs)){
                // getDeclaredConstructor返回所有申明的构造函数
                result = beanClass.getDeclaredConstructor().newInstance();
            }else {
                Class<?>[] argClasses = new Class[constructorArgs.size()];
                Object[] argObjects = new Object[constructorArgs.size()];
                for (int k = 0; k < constructorArgs.size(); ++k){
                    BeanDefinition.ConstructorArg arg = constructorArgs.get(k);
                    if (!arg.isRef()){
                        argClasses[k] = arg.getType();
                        argObjects[k] = arg.getArg();
                    }else {

                        BeanDefinition refBeanDefinition = beanDefinitions.get((String)arg.getArg());
                        // 判断参数对应类型的对象是否注入过
                        checkState(Objects.nonNull(refBeanDefinition), "Bean is not defined" + arg.getArg());
                        argClasses[k] = Class.forName(refBeanDefinition.getClassName());
                        argObjects[k] = createBean(refBeanDefinition);
                    }
                }
                // 对象注入
                result = beanClass.getConstructor(argClasses).newInstance(argObjects);
            }
            if (beanDefinition.isSingleton()){
                singletonObjects.putIfAbsent(beanDefinition.getId(), result);
                return singletonObjects.get(beanDefinition.getId());
            }
            return result;

        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
}
